#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include "data_type.h"
#include "alloc.h"
#include "memfunc.h"
#include "basefunc.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "memdb.h"
#include "message.h"
#include "ex_module.h"
#include "return_value.h"
#include "sys_func.h"
#include "tcm_constants.h"
#include "tcm_structures.h"
#include "tcmfunc.h"
#include "tcm_cube_struct.h"
#include "tcm_key_manage.h"
#include "tcm_key_desc.h"
#include "pcr_multirw.h"
#include "tcm_pik_desc.h"
// add para lib_include
//
BYTE Buf[DIGEST_SIZE*16];
int _proc_multiread_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd);
int _proc_multireset_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd);
int _proc_multiwrite_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd);
int _proc_multiread_quote(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd);

int pcr_multirw_init(void * sub_proc, void * para)
{
	int ret;
	// Init Tcm Func

	// add yorself's module init func here
	return 0;
}

int pcr_multirw_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here

	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
	
		if((type==TYPE(GENERAL_RETURN))&&(subtype==SUBTYPE(GENERAL_RETURN,STRING)))
		{
			ret=proc_pcr_multirw(sub_proc,recv_msg);
		}
		else
		{
            ex_module_sendmsg(sub_proc,recv_msg);
		}

	}
	return 0;
}


int proc_pcr_multirw( void * sub_proc, void * recv_msg)
{
    int ret;
    RECORD(GENERAL_RETURN,STRING) * pcr_cmd;

    ret = message_get_record(recv_msg,&pcr_cmd,0);
    if(ret<0)
        return -EINVAL;
     if(pcr_cmd ==NULL)
        return -EINVAL;
     if(Strcmp(pcr_cmd->name,"pcrread")==0)
     {
        return _proc_multiread_pcr(sub_proc,recv_msg,pcr_cmd);
     }
     if(Strcmp(pcr_cmd->name,"pcrwrite")==0)
     {
        return _proc_multiwrite_pcr(sub_proc,recv_msg,pcr_cmd);
     }
     if(Strcmp(pcr_cmd->name,"pcrreset")==0)
     {
        return _proc_multireset_pcr(sub_proc,recv_msg,pcr_cmd);
     }
     else if(Strcmp(pcr_cmd->name,"pcrquote")==0)
     {
        return _proc_multiread_pcr_quote(sub_proc,recv_msg,pcr_cmd);
        
     }
     else
        return -EINVAL;
}
int _proc_multiread_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd)
{
    int ret=0;
    int offset=0;

    int index;
    char temp_str[16];
    UINT32 result;

    BYTE pcr_buf[DIGEST_SIZE];
    TCM_PCR_COMPOSITE * read_result;

    if(Strcmp(read_cmd->name,"pcrread")!=0)
        return -EINVAL;

    read_result = Talloc0(sizeof(*read_result));   
    if(read_result ==NULL)
        return -ENOMEM;
    result = TCM_ExInitPcrComposite(read_result); 
    if(result !=0)
        return -EINVAL; 
    do{
        ret=Getfiledfromstr(temp_str,read_cmd->return_value+offset,'|',DIGEST_SIZE-offset);
        if(ret<0)
            return ret;
         if(ret==0)
            break;
        offset+=ret+1;
        index=atoi(temp_str);
        if((index<0)||(index>15))
            return -EINVAL;
		result=TCM_PcrRead(index,pcr_buf);
		if(result!=0)
				return result;
        result = TCM_ExDupPcrComposite(read_result,index,pcr_buf);
    }while(ret>0);
    
	message_add_expand_data(recv_msg,TYPE_PAIR(VTCM_PCR,TCM_PCR_COMPOSITE),read_result);
	ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}
int _proc_multireset_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd)
{
    int ret=0;
    int offset=0;

    int index;
    char temp_str[16];
    UINT32 result;

    BYTE pcr_buf[DIGEST_SIZE];
    TCM_PCR_COMPOSITE * read_result;

    if(Strcmp(read_cmd->name,"pcrreset")!=0)
        return -EINVAL;

    read_result = Talloc0(sizeof(*read_result));   
    if(read_result ==NULL)
        return -ENOMEM;
    result = TCM_ExInitPcrComposite(read_result); 
    if(result !=0)
        return -EINVAL; 
    do{
        ret=Getfiledfromstr(temp_str,read_cmd->return_value+offset,'|',DIGEST_SIZE-offset);
        if(ret<0)
            return ret;
         if(ret==0)
            break;
        offset+=ret+1;
        index=atoi(temp_str);
        if((index<0)||(index>15))
            return -EINVAL;
		result=TCM_PcrReset(index,pcr_buf);
		if(result!=0)
				return result;
        result = TCM_ExDupPcrComposite(read_result,index,pcr_buf);
    }while(ret>0);
    
	message_add_expand_data(recv_msg,TYPE_PAIR(VTCM_PCR,TCM_PCR_COMPOSITE),read_result);
	ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}

int _proc_multiwrite_pcr(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * write_cmd)
{
    int ret=0;
    int offset=0;

    int index;
    char temp_str[16];
    UINT32 result;

    BYTE pcr_buf[DIGEST_SIZE];
    TCM_PCR_COMPOSITE * read_result;
    RECORD(GENERAL_RETURN,BINDATA) * pcr_data;
    MSG_EXPAND * msg_expand;

    if(Strcmp(write_cmd->name,"pcrwrite")!=0)
        return -EINVAL;

    read_result = Talloc0(sizeof(*read_result));   
    if(read_result ==NULL)
        return -ENOMEM;
    result = TCM_ExInitPcrComposite(read_result); 
    if(result !=0)
        return -EINVAL; 

    index = atoi(write_cmd->return_value);
    if((index<0)||(index>15))
       return -EINVAL;

    ret = message_remove_expand(recv_msg,TYPE_PAIR(GENERAL_RETURN,BINDATA),&msg_expand);
    if(ret<0)
        return ret;
    pcr_data=msg_expand->expand;

    for(offset=0;offset<pcr_data->size;offset+=DIGEST_SIZE)
    {
		result=TCM_Extend(index,pcr_data->bindata+offset,pcr_buf);
		if(result!=0)
				return result;
    };

    result = TCM_ExDupPcrComposite(read_result,index,pcr_buf);
    
	message_add_expand_data(recv_msg,TYPE_PAIR(VTCM_PCR,TCM_PCR_COMPOSITE),read_result);
	ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}

int _proc_multiread_pcr_quote(void * sub_proc,void * recv_msg,RECORD(GENERAL_RETURN,STRING) * read_cmd)
{

    int ret=0;
    int offset=0;

    MSG_EXPAND * msg_expand;
    int index;
    char temp_str[16];
    UINT32 result;

    BYTE pcr_buf[DIGEST_SIZE];
    TCM_PCR_COMPOSITE * read_result;
    RECORD(TCM_PIK_DESC,PCRQUOTE) * quote_report;


    if(Strcmp(read_cmd->name,"pcrquote")!=0)
        return -EINVAL;

    ret = message_remove_expand(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),&msg_expand);
    if(ret<0)
        return -EINVAL;
    if(msg_expand==NULL)
        return -EINVAL;
    quote_report = msg_expand->expand;
    read_result = &(quote_report->pcrComp);
    
    result = TCM_ExInitPcrComposite(read_result); 
    if(result !=0)
        return -EINVAL; 
    do{
	
        ret =Getfiledfromstr(temp_str,read_cmd->return_value+offset,'|',DIGEST_SIZE-offset);
        if(ret<0)
            return ret;
        index=atoi(temp_str);
        if((index<0)||(index>15))
            return -EINVAL;
		result=TCM_PcrRead(index,pcr_buf);
		if(result!=0)
        {
            print_cubeerr("pcr_multirw : read pcr %d failed! error %d!\n",index,result);
				return result;
        }
        result = TCM_ExDupPcrComposite(read_result,index,pcr_buf);
	offset+=ret+1;
    }while(ret>0);
    
   message_add_expand_data(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),quote_report);
   ex_module_sendmsg(sub_proc,recv_msg);
   return ret;
}
